package drds.global_transaction.transaction_coordinator.store;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TransactionWriteFuture
{
	private static final long DEFAULT_WRITE_TIMEOUT = 5 * 1000;
	private static AtomicLong NEXT_WRITE_ID = new AtomicLong(0);
	@Setter
	@Getter
	private long id;
	@Setter
	@Getter
	private TransactionWriteStore transactionWriteStore;
	@Setter
	@Getter
	private CountDownLatch countDownLatch = new CountDownLatch(1);
	@Setter
	@Getter
	private long timeoutMills;
	@Setter
	@Getter
	private long start = System.currentTimeMillis();
	@Setter
	@Getter
	private volatile Object result;

	public TransactionWriteFuture(SessionStorable sessionRequest, OperationType operationType)
	{
		this(sessionRequest, operationType, DEFAULT_WRITE_TIMEOUT);
	}

	public TransactionWriteFuture(SessionStorable sessionRequest, OperationType operationType, long timeoutMills)
	{
		this.id = NEXT_WRITE_ID.incrementAndGet();
		this.transactionWriteStore = new TransactionWriteStore(sessionRequest, operationType);
		this.timeoutMills = timeoutMills;
	}

	public boolean isTimeout()
	{
		return System.currentTimeMillis() - start > timeoutMills;
	}

	public boolean get() throws InterruptedException
	{
		return get(timeoutMills, TimeUnit.MILLISECONDS);
	}

	public boolean get(long timeout, TimeUnit timeUnit) throws InterruptedException
	{
		this.timeoutMills = timeUnit.toMillis(timeout);
		boolean success = countDownLatch.await(timeout, timeUnit);
		if (!success)
		{
			log.error("write file timeout,cost" + (System.currentTimeMillis() - start) + " ms");
			return false;
		}
		if (result instanceof Exception)
		{
			log.error("write file error,msg:" + ((Exception) result).getMessage());
			return false;
		}

		return (result instanceof Boolean) ? ((Boolean) result).booleanValue() : false;
	}

	public void setResult(Object result)
	{
		if (null != result)
		{
			this.result = result;
			countDownLatch.countDown();
		}
	}

}
